package com.dbflow5.processor.definition.provider;

import com.dbflow5.contentprovider.annotation.Notify;
import com.dbflow5.contentprovider.annotation.NotifyMethod;
import com.dbflow5.processor.ClassNames;
import com.dbflow5.processor.ProcessorManager;
import com.dbflow5.processor.definition.Adders;
import com.dbflow5.processor.definition.BaseDefinition;
import com.squareup.javapoet.CodeBlock;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;

/**
 * Description: Writes code for [Notify] annotation.
 */
public class NotifyDefinition extends BaseDefinition implements Adders.CodeAdder {

    public NotifyDefinition(Notify notify, ExecutableElement typeElement, ProcessorManager processorManager) {
        super(typeElement, processorManager);
        paths = notify.paths();
        method = notify.notifyMethod();
        parent = ((TypeElement)typeElement.getEnclosingElement()).getQualifiedName().toString();
        methodName = typeElement.getSimpleName().toString();

        StringBuilder builder = new StringBuilder();
        for (VariableElement it : typeElement.getParameters()) {
            String typeName = it.asType().toString();
            if(typeName.equals("ohos.app.Context")){
                builder.append("getContext()");
            }else if(typeName.equals("ohos.utils.net.Uri")){
                builder.append("uri");
            }else if(typeName.equals("ohos.data.rdb.ValuesBucket")){
                builder.append("values");
            }else if(typeName.equals("long")){
                builder.append("id");
            }else if(typeName.equals("java.lang.String")){
                builder.append("where");
            }else if(typeName.equals("java.lang.String[]")){
                builder.append("whereArgs");
            }else {
                builder.append("");
            }
        }
        params = builder.toString();

        TypeMirror typeMirror = typeElement.getReturnType();
        if((ClassNames.URI + "[]").equals(typeMirror.toString())) {
            returnsArray = true;
        }else if(ClassNames.URI.toString().equals(typeMirror.toString())) {
            returnsSingle = true;
        }else {
            processorManager.logError("Notify method returns wrong type. It must return Uri or Uri[]");
        }
    }

    public String[] paths;
    public NotifyMethod method;
    private String parent;
    private String methodName;
    private String params;

    public boolean returnsArray = false;
    public boolean returnsSingle = false;

    @Override
    public CodeBlock.Builder addCode(CodeBlock.Builder code) {
        if (returnsArray) {
            code.addStatement("$T[] notifyUris$L = $L.$L($L)", ClassNames.URI,
                methodName, parent,
                methodName, params);
            code.beginControlFlow("for ($T notifyUri: notifyUris$L)", ClassNames.URI, methodName);
        } else {
            code.addStatement("$T notifyUri$L = $L.$L($L)", ClassNames.URI,
                methodName, parent,
                methodName, params);
        }
        code.addStatement("getContext().getContentResolver().notifyChange(notifyUri$L, null)",
                returnsArray? "" : methodName);
        if (returnsArray) {
            code.endControlFlow();
        }
        return code;
    }
}
